#include <cassert>
#include "exception.h"
#include "multiplexor_impl.h"

namespace Herm{

Multiplexor::Multiplexor(int size, int timeout, bool lt) 
{
	m_kqfd = kqueue();
	if (m_kqfd == -1)
		throw HERM_SOCKET_EXCEPTION("kqueue() failed", ST_OTHER);

	m_kevts = new struct kevent[size];
	m_size = size;

	// timeout must is >= -1, see Rector::Reactor()
	m_timeout = NULL; // default timeout == -1
	if (timeout != -1)
	{
		m_timeout = new struct timespec;

		if (timeout == 0) // Return immediately
			memset(m_timeout, 0, sizeof(struct timespec));
		else
		{
			m_timeout->tv_sec = timeout / 1000;
			m_timeout->tv_nsec = timeout % 1000 * 1000000; 
		}
	}
}

Multiplexor::~Multiplexor()
{
	close(m_kqfd);
	delete[] m_kevts;
	m_kevts = NULL;
}

void Multiplexor::Run()
{

	int evtCount = kevent(m_kqfd, NULL, 0, m_kevts, m_size, m_timeout);
	if (evtCount == -1)
		throw HERM_SOCKET_EXCEPTION("kevent() failed", ST_OTHER);

	for (int i = 0; i < evtCount; i++)
	{
		struct kevent& evt = m_kevts[i];
		IEventHandler* eh = reinterpret_cast<IEventHandler*>(evt.udata);

		if (evt.flags & EV_ERROR) // system error in evt.data
		{
			eh->Error(ST_OTHER, errno);
			continue;
		}

		int stateType = Herm::ST_SUCCESS;
		switch (evt.filter)
		{
		case EVFILT_READ:
			stateType = eh->Receive(evt.data);
			break;
		case EVFILT_WRITE:
			stateType = eh->Send(evt.data);
			break;
		default:
			assert(false);
			break;
		}

		if (stateType != Herm::ST_SUCCESS)
			eh->Error(stateType, errno);
	}
}

void Multiplexor::Register(IEventHandler* eh, MultiplexorMask mask)
{
	if (mask & Private::COMMON_READ_MASK)
	{ 
		if (!OperateHandler(EV_ADD, eh, EVFILT_READ))
			throw HERM_SOCKET_EXCEPTION("register READ failed", ST_OTHER);
	}

	if (mask & Private::COMMON_WRITE_MASK)
	{ 
		if (!OperateHandler(EV_ADD, eh, EVFILT_WRITE))
			throw HERM_SOCKET_EXCEPTION("register WRITE failed", ST_OTHER);
	}
}

void Multiplexor::Remove(IEventHandler* eh)
{
	// Unregister EVFILTE_READ
	if (!OperateHandler(EV_DELETE, eh, EVFILT_READ))
		throw HERM_SOCKET_EXCEPTION("Remove READ failed", ST_OTHER);

	// Unregister EVFILTE_WRITE
	if (!OperateHandler(EV_DELETE, eh, EVFILT_WRITE))
		throw HERM_SOCKET_EXCEPTION("Remove WRITE failed", ST_OTHER);
}

void Multiplexor::EnableMask(IEventHandler* eh, MultiplexorMask mask)
{
	if (mask & Private::COMMON_READ_MASK)
	{ 
		if (!OperateHandler(EV_ENABLE, eh, EVFILT_READ))
			throw HERM_SOCKET_EXCEPTION("EV_ENABLE READ failed", ST_OTHER);
	}

	if (mask & Private::COMMON_WRITE_MASK)
	{ 
		if (!OperateHandler(EV_ENABLE, eh, EVFILT_WRITE))
			throw HERM_SOCKET_EXCEPTION("EV_ENABLE WRITE failed", ST_OTHER);
	}
}

void Multiplexor::DisableMask(IEventHandler* eh, MultiplexorMask mask)
{
	if (mask & Private::COMMON_READ_MASK)
	{ 
		if (!OperateHandler(EV_DISABLE, eh, EVFILT_READ))
			throw HERM_SOCKET_EXCEPTION("EV_DISABLE READ failed", ST_OTHER);
	}

	if (mask & Private::COMMON_WRITE_MASK)
	{ 
		if (!OperateHandler(EV_DISABLE, eh, EVFILT_WRITE))
			throw HERM_SOCKET_EXCEPTION("EV_DISABLE WRITE failed", ST_OTHER);
	}
}

} // end namespace Herm
